package com.ricchieri.manage.bean;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;

import com.ricchieri.common.BusinessSettings;
import com.ricchieri.datamodel.UserEmailDataModel;
import com.ricchieri.datamodel.UserPhoneDataModel;
import com.ricchieri.filter.UserFilter;
import com.ricchieri.model.DocumentType;
import com.ricchieri.model.EmailType;
import com.ricchieri.model.PhoneType;
import com.ricchieri.model.Role;
import com.ricchieri.model.User;
import com.ricchieri.model.UserEmail;
import com.ricchieri.model.UserPhone;
import com.ricchieri.model.UserRole;
import com.ricchieri.service.interf.IDocumentTypeService;
import com.ricchieri.service.interf.IEmailTypeService;
import com.ricchieri.service.interf.IPhoneTypeService;
import com.ricchieri.service.interf.IRoleService;
import com.ricchieri.service.interf.IUserService;
import com.ricchieri.util.FacesUtil;
import com.ricchieri.util.StringUtils;

@ViewScoped
public abstract class CommonUserManageBean extends GenericManageBean {
	
	private static final long serialVersionUID = 2594635211753585244L;

	@ManagedProperty(value = "#{UserService}")
	IUserService userService;
	
	@ManagedProperty(value = "#{DocumentTypeService}")
	IDocumentTypeService documentTypeService;
	
	@ManagedProperty(value = "#{EmailTypeService}")
	IEmailTypeService emailTypeService;
	
	@ManagedProperty(value = "#{PhoneTypeService}")
	IPhoneTypeService phoneTypeService;
	
	@ManagedProperty(value = "#{RoleService}")
	IRoleService roleService;
	
	private User user;
	
	private Map<String,String> documents = null;
	private Map<String,String> allPhonesTypes = null;
	private Map<String,String> allEmailsTypes = null;
	private Map<String,String> roleTypes = null;
	
	private Map<String,String> phonesTypes = null;
	private Map<String,String> emailsTypes = null;
	
	private String previousDni = "";

	private List<String> selectedRoles;
	
	private List<UserPhone> phones;	
	private List<UserEmail> emails;
	
	private UserPhone selectedUserPhone;
	private UserPhoneDataModel phoneDataModel;
	
	private UserEmail selectedUserEmail;
	private UserEmailDataModel emailDataModel;
	
	private String phone;
	private String number;
	private String emailType;
	private String email;
	private String documentType;
	
	@PostConstruct
	public void init() {
		user = (User) FacesUtil.getParametersFlash(BusinessSettings.KEY_USER);
		
		if(isRequeriedUser() && user == null) {
			FacesUtil.redirectToNavigationCase(BusinessSettings.SEARCH_USER);
		}
	}
	
	public List<String> getSelectedRoles() {
		if(selectedRoles == null) {
			selectedRoles = new ArrayList<String>();
		}
		return selectedRoles;
	}

	public void setSelectedRoles(List<String> selectedRole) {
		this.selectedRoles = selectedRole;
	}

	public IUserService getUserService() {
		return userService;
	}

	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	public Map<String, String> getRoleTypes() {
		if(roleTypes == null) {
			roleTypes = new TreeMap<String, String>();
			List<Role> rol = roleService.getAllRole();
			for (Role role : rol) {
				roleTypes.put(this.obtainDescription(role.getDescription()), String.valueOf(role.getId()));
			}
		}
		return roleTypes;
	}

	public void setRoleTypes(Map<String, String> roleTypes) {
		this.roleTypes = roleTypes;
	}
	
	
	public Map<String, String> getDocuments() {
		if(documents == null) {
			documents = this.getDocumentTypeService().getComboDocuments();
		}
		return documents;
	}

	public void setDocuments(Map<String, String> documents) {
		this.documents = documents;
	}


	public IDocumentTypeService getDocumentTypeService() {
		return documentTypeService;
	}

	public void setDocumentTypeService(IDocumentTypeService documentTypeService) {
		this.documentTypeService = documentTypeService;
	}
	
	protected DocumentType obtainDocumentType(String id) {
		List<DocumentType> docu = documentTypeService.getAllDocumentsTypes();
		for (DocumentType documentType : docu) {
			if(id.equals(String.valueOf(documentType.getId()))) {
				return documentType;
			}
		}
		return null;
	}

	public Map<String, String> getPhonesTypes() {
		if(phonesTypes == null) {
			phonesTypes = new TreeMap<String, String>();
			List<PhoneType> ems = phoneTypeService.getAllPhoneTypes();
			for (PhoneType eType : ems) {
				phonesTypes.put(this.obtainDescription(eType.getDescription()), String.valueOf(eType.getId()));
			}
			allPhonesTypes = new TreeMap<String, String>(phonesTypes);
			this.modifyPhonesTypes();
		}
		return phonesTypes;
	}


	public void setPhonesTypes(Map<String, String> phonesTypes) {
		this.phonesTypes = phonesTypes;
	}


	public Map<String, String> getEmailsTypes() {
		if(emailsTypes == null) {
			emailsTypes = new TreeMap<String, String>();
			List<EmailType> ems = emailTypeService.getAllEmailTypes();
			for (EmailType eType : ems) {
				emailsTypes.put(this.obtainDescription(eType.getDescription()), String.valueOf(eType.getId()));
			}
			allEmailsTypes = new TreeMap<String, String>(emailsTypes);
			this.modifyEmailsTypes();
		}
		return emailsTypes;
	}

	public void setEmailsTypes(Map<String, String> emailsTypes) {
		this.emailsTypes = emailsTypes;
	}

	public IEmailTypeService getEmailTypeService() {
		return emailTypeService;
	}

	public void setEmailTypeService(IEmailTypeService emailTypeService) {
		this.emailTypeService = emailTypeService;
	}

	protected EmailType obtainUserEmail(String id) {
		List<EmailType> ems = emailTypeService.getAllEmailTypes();
		for (EmailType eType : ems) {
			if(id.equals(String.valueOf(eType.getId()))) {
				return eType;
			}
		}
		return null;
	}
	
	protected List<UserRole> generateRoles(User user) {
		List<UserRole> roles = new ArrayList<UserRole>();
		for (String role : selectedRoles) {
			roles.add(new UserRole(this.obtainRole(role), user));
		}
		return roles;
	}
	
	
	protected Role obtainRole(String id) {
		List<Role> ems = roleService.getAllRole();
		for (Role eType : ems) {
			if(id.equals(String.valueOf(eType.getId()))) {
				return eType;
			}
		}
		return null;
	}
	
	protected PhoneType obtainUserPhone(String id) {
		List<PhoneType> ems = phoneTypeService.getAllPhoneTypes();
		for (PhoneType eType : ems) {
			if(id.equals(String.valueOf(eType.getId()))) {
				return eType;
			}
		}
		return null;
	}

	public IPhoneTypeService getPhoneTypeService() {
		return phoneTypeService;
	}

	public void setPhoneTypeService(IPhoneTypeService phoneTypeService) {
		this.phoneTypeService = phoneTypeService;
	}

	public Map<String, String> getAllPhonesTypes() {
		return allPhonesTypes;
	}

	public void setAllPhonesTypes(Map<String, String> allPhonesTypes) {
		this.allPhonesTypes = allPhonesTypes;
	}

	public Map<String, String> getAllEmailsTypes() {
		return allEmailsTypes;
	}

	public void setAllEmailsTypes(Map<String, String> allEmailsTypes) {
		this.allEmailsTypes = allEmailsTypes;
	}

	public IRoleService getRoleService() {
		return roleService;
	}

	public void setRoleService(IRoleService roleService) {
		this.roleService = roleService;
	}
	
	protected abstract String getFormName();
	
	protected Boolean validateForm() {

		Boolean isCorrect = Boolean.TRUE;
		Boolean isCorrectDocumentNumber = Boolean.TRUE;
		if(this.getEmails().isEmpty()) {
			FacesUtil.showFatalMessage(getFormName(), "requiredEmail");
			isCorrect = Boolean.FALSE;
		} else {
			if(this.getSelectedUserEmail() == null) {
				FacesUtil.showFatalMessage(getFormName(), "requiredEmailPrincipal");
				isCorrect = Boolean.FALSE;
			}
		}
		
		if(this.getPhones().isEmpty()) {
			FacesUtil.showFatalMessage(getFormName(), "requiredPhone");
			isCorrect = Boolean.FALSE;
		} else {
			if(this.getSelectedUserPhone() == null) {
				FacesUtil.showFatalMessage(getFormName(), "requiredPhonePrincipal");
				isCorrect = Boolean.FALSE;
			}
		}
		
		
		if(this.getDocumentType().equals(BusinessSettings.DOCUMENT_DNI)) {
			if(getUser().getDni().length() != 8) {
				isCorrectDocumentNumber = Boolean.FALSE;
				isCorrect = Boolean.FALSE;
				FacesUtil.addErrorMsg(getFormName().concat(":dni"), "dniLengthWrong");				
			} else if(!StringUtils.isNumeric(getUser().getDni())) {
				isCorrectDocumentNumber = Boolean.FALSE;
				isCorrect = Boolean.FALSE;
				FacesUtil.addErrorMsg(getFormName().concat(":dni"), "numberFormatWrong");
			}
		}
		
		if(isCorrectDocumentNumber) {
			UserFilter userFilter =  new UserFilter();
			userFilter.setDni(getUser().getDni());
			userFilter.setDocumentType(this.getDocumentType());
			int count = userService.getAllUserCountByFilter(userFilter);
			
			if(count >0 && !previousDni.equals(getUser().getDni())) {
				FacesUtil.showFatalMessage(getFormName(), "dniExist");
				isCorrect = Boolean.FALSE;
			}
		}
		
		if(this.getSelectedRoles() == null || this.getSelectedRoles().isEmpty()) {
			FacesUtil.showFatalMessage(getFormName(), "requiredRoles");
			isCorrect = Boolean.FALSE;
		}
		
		return isCorrect;
	}

	public List<UserPhone> getPhones() {
		if(phones == null) {
			phones = new ArrayList<UserPhone>();
		}
		return phones;
	}

	public void setPhones(List<UserPhone> phones) {
		this.phones = phones;
	}

	public List<UserEmail> getEmails() {
		if(emails == null) {
			emails = new ArrayList<UserEmail>();
		}
		
		return emails;
	}


	public void setEmails(List<UserEmail> emails) {
		this.emails = emails;
	}
	
	public void addEmail() {
		
		if(StringUtils.isEmpty(this.getEmail())) {
			FacesUtil.addErrorMsg(getFormName().concat(":email"), "requiredMail");
		} else if(existEmail()) {
			FacesUtil.addErrorMsg(getFormName().concat(":email"), "emailExist");
		} else {
			getEmails().add(new UserEmail(this.getEmail(), this.obtainUserEmail(this.getEmailType()), this.getUser()));
			emailDataModel = new UserEmailDataModel(getEmails());
			
			if(this.getSelectedUserEmail() == null){
				this.setSelectedUserEmail(getEmails().get(0));
			}
			
			this.modifyEmailsTypes();
			this.setEmail("");
			this.setEmailType("");
		}	
	}
	
	private Boolean existEmail() {
		for (UserEmail userEmail : getEmails()) {
			if(userEmail.getEmail().equals(this.getEmail())) {
				return Boolean.TRUE;
			}
		}
		return Boolean.FALSE;
	}
	
	protected void modifyEmailsTypes() {
		
		Boolean exist = Boolean.FALSE;
		Map<String, String> newEmailsTypes = new TreeMap<String, String>();
		for (String emailTy : this.getAllEmailsTypes().keySet()) {
			for (UserEmail userEmail : getEmails()) {
				
				if(String.valueOf(userEmail.getEmailType().getId()).equals(this.getAllEmailsTypes().get(emailTy))) {
					exist = Boolean.TRUE;
					break;
				}
			}
			
			if(!exist) {
				newEmailsTypes.put(emailTy, this.getAllEmailsTypes().get(emailTy));
			}
			exist = Boolean.FALSE;
		}
		this.setEmailsTypes(newEmailsTypes);
	}
	
	protected void modifyPhonesTypes() {
		
		Boolean exist = Boolean.FALSE;
		Map<String, String> newPhonesTypes = new TreeMap<String, String>();
		String value;
		for (String phoneTy : this.getAllPhonesTypes().keySet()) {
			value = this.getAllPhonesTypes().get(phoneTy);
			for (UserPhone userPhone : getPhones()) {
				
				if(String.valueOf(userPhone.getPhoneType().getId()).equals(value)) {
					exist = Boolean.TRUE;
					break;
				}
			}
			
			if(!exist) {
				newPhonesTypes.put(phoneTy, this.getAllPhonesTypes().get(phoneTy));
			}
			exist = Boolean.FALSE;
		}
		this.setPhonesTypes(newPhonesTypes);
	}
	
	
	public void addPhone() {
		
		if(StringUtils.isEmpty(this.getNumber())) {
			FacesUtil.addErrorMsg(getFormName().concat(":number"), "requiredNumber");
		} else if(existPhone()) {
			FacesUtil.addErrorMsg(getFormName().concat(":number"), "phoneExist");
		} else {
			getPhones().add(new UserPhone(this.getNumber(), this.obtainUserPhone(this.getPhone()), this.getUser()));
			phoneDataModel = new UserPhoneDataModel(getPhones());
			
			if(this.getSelectedUserPhone() == null){
				this.setSelectedUserPhone(getPhones().get(0));
			}
			
			this.modifyPhonesTypes();
			this.setPhone("");
			this.setNumber("");
		}		
	}
	
	private Boolean existPhone() {
		for (UserPhone userPhone : this.getPhones()) {
			if(userPhone.getNumber().equals(this.getNumber())) {
				return Boolean.TRUE;
			}
		}
		return Boolean.FALSE;
	}

	public UserPhone getSelectedUserPhone() {
		return selectedUserPhone;
	}

	public void setSelectedUserPhone(UserPhone selectedUserPhone) {
		this.selectedUserPhone = selectedUserPhone;
	}

	public UserPhoneDataModel getPhoneDataModel() {
		return phoneDataModel;
	}

	public void setPhoneDataModel(UserPhoneDataModel phoneDataModel) {
		this.phoneDataModel = phoneDataModel;
	}

	public UserEmail getSelectedUserEmail() {
		return selectedUserEmail;
	}

	public void setSelectedUserEmail(UserEmail selectedUserEmail) {
		this.selectedUserEmail = selectedUserEmail;
	}

	public UserEmailDataModel getEmailDataModel() {
		return emailDataModel;
	}

	public void setEmailDataModel(UserEmailDataModel emailDataModel) {
		this.emailDataModel = emailDataModel;
	}
	
	
	public void deleteUserEmail(UserEmail mail) {
		getEmails().remove(mail);
		emailDataModel = new UserEmailDataModel(getEmails());
		this.modifyEmailsTypes();
	}
	
	public void deleteUserPhone(UserPhone phone) {
		getPhones().remove(phone);
		phoneDataModel = new UserPhoneDataModel(getPhones());
		this.modifyPhonesTypes();
	}
	
	public String getDocumentType() {
		return documentType;
	}

	public void setDocumentType(String documentType) {
		this.documentType = documentType;
	}
	
	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getNumber() {
		return number;
	}

	public void setNumber(String number) {
		this.number = number;
	}
	
	public String getEmailType() {
		return emailType;
	}

	public void setEmailType(String emailType) {
		this.emailType = emailType;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
	
	public User getUser() {
		if(user == null) {
			user =  new User();
		}
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	protected void setDefaultEmail() {
		for (UserEmail userEmail : this.getEmails()) {
			if(userEmail.getEmail().equals(this.getSelectedUserEmail().getEmail())) {
				userEmail.setIsDefault(Boolean.TRUE);
			} else {
				userEmail.setIsDefault(Boolean.FALSE);
			}
		}
	}
	
	protected void setDefaultPhone() {
		for (UserPhone userPhone : this.getPhones()) {
			if(userPhone.getNumber().equals(this.getSelectedUserPhone().getNumber())) {
				userPhone.setIsDefault(Boolean.TRUE);
			}
			else {
				userPhone.setIsDefault(Boolean.FALSE);
			}
		}
	}
	
	public String getPreviousDni() {
		return previousDni;
	}

	public void setPreviousDni(String previousDni) {
		this.previousDni = previousDni;
	}

	public Boolean isRequiredCuil() {
		String admin = FacesUtil.getMessage(BusinessSettings.ROLE_ADMIN);
		String driver = FacesUtil.getMessage(BusinessSettings.ROLE_DRIVER);
		String operator = FacesUtil.getMessage(BusinessSettings.ROLE_OPERATOR);
		
		if (getSelectedRoles() != null) {
			for (String role : getSelectedRoles()) {
				if(getRoleTypes().get(admin).equals(role) ||
						getRoleTypes().get(driver).equals(role) ||
						getRoleTypes().get(operator).equals(role)) {
					return Boolean.TRUE;
				}
			}
		}
		return Boolean.FALSE;
	}
	
	public abstract String save();
	public abstract Boolean isRequeriedUser();
	
}
